#define _CRT_SECURE_NO_WARNINGS 1

//#include <iostream>
//#include <vector>
//#include <string>
//#include <sstream>
//#include <queue>
//#include <algorithm>
//#include <climits>
//
//
//using namespace std;
//
//struct TreeNode {
//    int val;
//    TreeNode* left;
//    TreeNode* right;
//    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
//};
//
//TreeNode* buildTree(const vector<string>& tokens) {
//    if (tokens.empty() || tokens[0] == "N") return nullptr;
//    TreeNode* root = new TreeNode(stoi(tokens[0]));
//    queue<TreeNode*> q;
//    q.push(root);
//    int index = 1;
//    while (!q.empty() && index < tokens.size()) {
//        TreeNode* current = q.front();
//        q.pop();
//        if (index < tokens.size() && tokens[index] != "N") {
//            current->left = new TreeNode(stoi(tokens[index]));
//            q.push(current->left);
//        }
//        index++;
//        if (index < tokens.size() && tokens[index] != "N") {
//            current->right = new TreeNode(stoi(tokens[index]));
//            q.push(current->right);
//        }
//        index++;
//    }
//    return root;
//}
//
//void dfs(TreeNode* node, long long& dp0, long long& dp1, long long& dp2) {
//    if (!node) {
//        dp0 = LLONG_MAX/2;
//        dp1 = 0;
//        dp2 = 0;
//        return;
//    }
//
//    long long left0, left1, left2;
//    long long right0, right1, right2;
//
//    dfs(node->left, left0, left1, left2);
//    dfs(node->right, right0, right1, right2);
//
//    dp0 = 1 + min(left0, min(left1, left2)) + min(right0, min(right1, right2));
//    dp1 = min(left0 + min(right0, right1), right0 + min(left0, left1));
//    dp2 = left1 + right1;
//
//}
//
//int main() {
//    string line;
//    getline(cin, line);
//    vector<string> tokens;
//    string token;
//    istringstream iss(line);
//    while (iss >> token) {
//        tokens.push_back(token);
//    }
//    if (tokens.empty()) {
//        cout << 0 << endl;
//        return 0;
//    }
//    TreeNode* root = buildTree(tokens);
//    long long dp0, dp1, dp2;
//    dfs(root, dp0, dp1, dp2);
//    cout << min(dp0, dp1) << endl;
//    return 0;
//}



//#include <iostream>
//#include <vector>
//#include <algorithm>
//using namespace std;
//
//int main() 
//{
//    int n, m;
//    cin >> n >> m;
//
//    vector<int> have(11, 0);
//    vector<int> need(11, 0);
//    for (int i = 0; i < n; i++)
//    {
//        int level = 0;
//        cin >> level;
//        if (level >= 1 && level <= 10) 
//            have[level]++;
//    }
//    int k = 5;
//    while (k--);
//
//    for (int i = 0; i < m; i++) 
//    {
//        int level = 0;
//        cin >> level;
//        if (level >= 1 && level <= 10) 
//            need[level]++;
//    }
//
//    vector<int> avail = have;
//    int total = 0;
//    for (int i = 1; i <= 10; i++) 
//    {
//        int take = min(avail[i], need[i]);
//        total += take;
//        avail[i] -= take;
//        if (i < 10) 
//            avail[i + 1] += avail[i] / 2;
//    }
//    int t = 5;
//    while (t--);
//    if (total < m) 
//        cout << total << endl;
//    else 
//    {
//        vector<int> required(11, 0);
//        for (int i = 1; i <= 10; i++) 
//            required[i] = need[i];
//        for (int i = 10; i >= 1; i--) 
//        {
//            if (required[i] > have[i]) 
//            {
//                int deficit = required[i] - have[i];
//                required[i - 1] += 2 * deficit;
//            }
//        }
//        int ret = 0;
//        for (int i = 1; i <= 10; i++) 
//            ret += min(required[i], have[i]);
//        cout << ret << endl;
//    }
//
//    return 0;
//}

//#include <bits/stdc++.h>
//#include <vector>
//#include <string>
//#include <iostream>
//#include <queue>
//using namespace std;
//
//const int INF = 0x3f3f3f3f;
//int n, m;
//vector<string> grid;
//vector<pair<int, int>> points[6];
//pair<int, int> start;
//
//int dx[4] = { 0, 0, 1, -1 };
//int dy[4] = { 1, -1, 0, 0 };
//
//int main() {
//    cin >> n >> m;
//    grid.resize(n);
//    for (int i = 0; i < n; i++) {
//        cin >> grid[i];
//    }
//
//    for (int i = 0; i < n; i++) 
//    {
//        for (int j = 0; j < m; j++) 
//        {
//            if (grid[i][j] == 'S') 
//            {
//                start = { i, j };
//            }
//            else if (isdigit(grid[i][j]))
//            {
//                int id = grid[i][j] - '0';
//                if (id >= 1 && id <= 5) 
//                {
//                    points[id].push_back({ i, j });
//                }
//            }
//        }
//    }
//
//    vector<vector<int>> dist(n, vector<int>(m, INF));
//    priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<pair<int, pair<int, int>>>> pq;
//    dist[start.first][start.second] = 0;
//    pq.push({ 0, start });
//
//    while (!pq.empty()) {
//        auto t = pq.top();
//        auto d = t.first;
//        auto p = t.second;
//        pq.pop();
//        int x = p.first, y = p.second;
//        if (d != dist[x][y]) continue;
//        for (int k = 0; k < 4; k++) {
//            int nx = x + dx[k], ny = y + dy[k];
//            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
//            if (grid[nx][ny] == '#') continue;
//            if (dist[nx][ny] > d + 1) {
//                dist[nx][ny] = d + 1;
//                pq.push({ dist[nx][ny], {nx, ny} });
//            }
//        }
//    }
//
//    vector<int> current_dp;
//    vector<pair<int, int>> current_points = points[1];
//    for (auto& p : points[1]) {
//        current_dp.push_back(dist[p.first][p.second]);
//    }
//
//    for (int id = 2; id <= 5; id++) {
//        dist.assign(n, vector<int>(m, INF));
//        priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<pair<int, pair<int, int>>>> pq2;
//        for (int i = 0; i < current_points.size(); i++) {
//            int x = current_points[i].first, y = current_points[i].second;
//            if (current_dp[i] < INF) {
//                dist[x][y] = current_dp[i];
//                pq2.push({ current_dp[i], {x, y} });
//            }
//        }
//
//        while (!pq2.empty()) {
//            auto t = pq2.top();
//            auto d = t.first;
//            auto p = t.second;
//            pq2.pop();
//            int x = p.first, y = p.second;
//            if (d != dist[x][y]) continue;
//            for (int k = 0; k < 4; k++) {
//                int nx = x + dx[k], ny = y + dy[k];
//                if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
//                if (grid[nx][ny] == '#') continue;
//                if (dist[nx][ny] > d + 1) {
//                    dist[nx][ny] = d + 1;
//                    pq2.push({ dist[nx][ny], {nx, ny} });
//                }
//            }
//        }
//
//        current_points = points[id];
//        current_dp.clear();
//        for (auto& p : points[id]) {
//            current_dp.push_back(dist[p.first][p.second]);
//        }
//    }
//
//    int ans = *min_element(current_dp.begin(), current_dp.end());
//    cout << ans << endl;
//
//    return 0;
//}

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    int n;
    cin >> n;

    map<int, int> cat1, cat2, cat3, cat4;

    for (int i = 0; i < n; i++) 
    {
        int x, y, z;
        cin >> x >> y >> z;
        if (y == 1 && z == 1) 
            cat1[x]++;
        else if (y == 1 && z == 2) 
            cat2[x]++;
        else if (y == 2 && z == 1) 
            cat3[x]++;
        else if (y == 2 && z == 2) 
            cat4[x]++;
    }

    long long total = 0;

    vector<map<int, int>> categories = { cat1, cat2, cat3, cat4 };
    for (auto& cat : categories) 
    {
        if (cat.empty()) 
            continue;
        vector<int> counts;
        for (auto& p : cat) 
            counts.push_back(p.second);
        sort(counts.begin(), counts.end());
        int m = counts.size();
        vector<long long> prefix(m + 1, 0);
        for (int i = 0; i < m; i++) 
            prefix[i + 1] = prefix[i] + counts[i];
        long long S = prefix[m];
        int k_max = S / 3;
        int low = 0, high = k_max;
        int ans_cat = 0;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            auto it = lower_bound(counts.begin(), counts.end(), mid);
            int idx = it - counts.begin();
            long long sum_min = prefix[idx] + (m - idx) * (long long)mid;
            if (sum_min >= 3LL * mid) {
                ans_cat = mid;
                low = mid + 1;
            }
            else {
                high = mid - 1;
            }
        }
        total += ans_cat;
    }

    cout << total << endl;

    return 0;
}
